﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace EasyMarmat
{
    /// <summary>
    /// 基于程序集反射实现的命令工厂。
    /// </summary>
    public class AssemblyCommandFactory : ICommandFactory
    {
        /// <summary>
        /// 缓存模块，用于缓存已经执行过的请求，下次请求直接从缓存中获取。
        /// </summary>
        private static Dictionary<Type, Type> cache;
        private readonly System.Reflection.Assembly[] assemblies;

        /// <summary>
        /// 构建基于程序集反射实现的命令工厂。
        /// </summary>
        /// <param name="type"></param>
        public AssemblyCommandFactory(Type type)
        {
            if (type is null)
                throw new ArgumentNullException($"{nameof(type)} 参数不能为null");
            if (cache is null)
                cache = new Dictionary<Type, Type>();
            this.assemblies = new Assembly[] { type.Assembly };
        }

        /// <summary>
        /// 构建基于程序集反射实现的命令工厂。
        /// </summary>
        /// <param name="assembly"></param>
        public AssemblyCommandFactory(System.Reflection.Assembly assembly)
        {
            if (assembly is null)
                throw new ArgumentNullException($"{nameof(assembly)} 参数不能为null");
            if (cache is null)
                cache = new Dictionary<Type, Type>();
            this.assemblies = new Assembly[] { assembly };
        }

        /// <summary>
        /// 构建基于程序集反射实现的命令工厂。
        /// </summary>
        /// <param name="assemblies"></param>
        public AssemblyCommandFactory(params System.Reflection.Assembly[] assemblies)
        {
            if (assemblies is null)
                throw new ArgumentNullException($"{nameof(assemblies)} 参数不能为null");
            if (cache is null)
                cache = new Dictionary<Type, Type>();
            this.assemblies = assemblies;
        }



        /// <summary>
        /// 获取接口对应的服务实例。
        /// </summary>
        /// <typeparam name="TInterface">接口泛型</typeparam>
        /// <returns></returns>
        public TInterface GetService<TInterface>() where TInterface : class
        {
            Type type = typeof(TInterface);
            Type result_type = null;
            if (cache.ContainsKey(type))
                result_type = cache[type];
            else
            {
                foreach (var assembly in assemblies)
                {
                    Type[] types = assembly.GetExportedTypes();
                    types = types.Where(x => x.IsAbstract == false && type.IsAssignableFrom(x)).ToArray();
                    foreach (Type item in types)
                    {
                        result_type = item;
                        break;
                    }
                }
            }

            TInterface instance = default;
            if (result_type != null)
            {
                instance = (TInterface)result_type.Assembly.CreateInstance(result_type.FullName, false);
            }
            return instance;
        }
    }
}
